package com.nny.alarm.widget;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.os.Build;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.nny.alarm.R;

public class HandView extends View
{
	int mnRadius = 0;
	TextPaint mTextPaint;
	int mnTextHeight;
	int mnMarkWidth;
	int mnMarkHeight;
	HandViewAdapter mAdapter;
	Point mCenter;
	Bitmap[] mMarkers;
	HandGestureDetector mGesture;
	float mfBearing;
	OnMarkListener mOnMarkListener;
	
	public HandView(Context context)
	{
		super(context);
		initView();
	}

	public HandView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		initView();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		return mGesture.onTouchEvent(event);
	}

	@Override
	protected void onDraw(Canvas canvas)
	{
		int height = getMeasuredHeight();
		int width = getMeasuredWidth();

		mCenter.x = width / 2;
		mCenter.y = height / 2;
		drawDial(canvas, width, height);
		drawMarker(canvas, width, height);
	}

	public boolean onMove(float bearing)
	{
		if(null == mAdapter)
			return false;
		final int current = getPosition(mfBearing);
		
		mfBearing = bearing;		
		final int next = getPosition(mfBearing);
		if(current != next)
		{
			//audio play
			if(mOnMarkListener != null)
				mOnMarkListener.onMarkChanged(next);
		}
		invalidate();		
		return false;
	}

	public void onMarked()
	{
		if(mAdapter == null)
			return;
		
		mfBearing = getNearBearing(mfBearing);
		invalidate();
		if(null != mOnMarkListener)
			mOnMarkListener.onMarked(getPosition(mfBearing));
		mGesture.mfBearing = mfBearing;
	}
	
	public void setRadious(int radious)
	{
		mnRadius = radious;
		invalidate();
	}
	
	public void setAdapter(HandViewAdapter adapter)
	{
		mAdapter = adapter;
	}
	
	public void setOnMarkListener(OnMarkListener l)
	{
		mOnMarkListener = l;
	}
	
	public void setPosition(int position)
	{
		mfBearing = toBearing(position);
		mGesture.mfBearing = mfBearing;
	}
	
	public float getMaxBearing()
	{
		return toBearing(mAdapter.getMax());
	}
	
	protected void drawDial(Canvas canvas, int w, int h)
	{	
		//draw markers
		if(mAdapter == null)return;

		canvas.save();
		Path path = new Path();
		path.moveTo(mCenter.x + mnTextHeight / 2, mCenter.y - (mnRadius));
		path.lineTo(mCenter.x  + mnTextHeight / 2, -100);
		
		int count = mAdapter.getCount();
		float degree = 360.0f / (float)count;
		
		for (int i = 0; i < count; i++) 
		{
			mTextPaint.setColor(mAdapter.getTextColor(i));	
			canvas.drawTextOnPath(mAdapter.getMarkText(i), path, 0, 0, mTextPaint);
			canvas.rotate(degree, mCenter.x , mCenter.y);
		}
		canvas.restore();
	}
	
	protected void drawMarker(Canvas canvas, int w, int h)
	{	
		canvas.save();
		canvas.rotate(mfBearing, mCenter.x , mCenter.y);
		canvas.drawBitmap(mMarkers[mGesture.mbDragging ? 0 : 1], mCenter.x - mnMarkWidth / 2, mCenter.y - mnRadius, null);
		canvas.restore();
	}
	
	protected void initView()
	{
		setSoftwareMode();
		mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
		mTextPaint.setColor(Color.BLACK);
		mTextPaint.setFakeBoldText(true);
		mTextPaint.setSubpixelText(true);
		mTextPaint.setTextAlign(Paint.Align.LEFT);
		mTextPaint.setTextSize(14);
		
		mnTextHeight = (int) mTextPaint.measureText("yY");
		
		mCenter = new Point(0, 0);
		
		mMarkers = new Bitmap[2];
		mMarkers[0] = BitmapFactory.decodeResource(getResources(), R.drawable.dial_marker_pressed);
		mMarkers[1] = BitmapFactory.decodeResource(getResources(), R.drawable.dial_marker_normal);
		
		mnMarkWidth = mMarkers[0].getWidth();
		mnMarkHeight = mMarkers[1].getHeight();
		
		mGesture = new HandGestureDetector(this);
	}
	
	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	public void setSoftwareMode()
	{
		if(android.os.Build.VERSION.SDK_INT >= 11){
			setLayerType(View.LAYER_TYPE_SOFTWARE, null);
		}
	}
	
	
	private final float getNearBearing(float bearing)
	{
		if(null == mAdapter)
			return bearing;	
		float degree = 360.0f / (float)mAdapter.getCount();
		if(bearing > 360 - degree / 2)
			return 0;
		
		final float max = getMaxBearing();
		if(bearing > max + degree / 2)
			return max;		
		
		return degree * getPosition(bearing);
	}
	
	private final float toBearing(int position)
	{
		if(null == mAdapter)
			return 0;
		float degree = 360.0f / (float)mAdapter.getCount();
		return degree * position;
	}
	
	public boolean isMarked(float bearing)
	{
		if(mAdapter == null)
			return false;
		float degree = 360.0f / (float)18; 

//		Log.d("zzm.2", String.format("a=%f,b=%f,degree=%f", bearing, mfBearing, degree));
		final float min = mfBearing - degree;
		final float max = mfBearing + degree;
		float th = 360 - degree;
		if(min <= 0 && (bearing > th || bearing < max))
		{
			return true;
		}
		return (bearing < max && bearing > min);
	}
	
	private int getPosition(float bearing)
	{
		if(mAdapter == null)
			return 0;
		final int count = mAdapter.getCount();
		float degree = 360.0f / (float)count; 
		int position = (int)(bearing / degree);
		//不能用bearing%degree,存在精度问题
		float offset = Math.abs(bearing - degree * position);
		if(bearing > 360.0f - degree / 2)
		{
			return 0;
		}
		if(offset > degree / 2)
			return position + 1;
		else 
			return position;
	}
	
	public static interface HandViewAdapter
	{
		public int getCount();
		public String getMarkText(int index);
		public int getTextColor(int index);
		public int getMax();
	}
	
	public static interface OnMarkListener
	{
		public boolean onMarkChanged(int position);
		public void onMarked(int position);
	}
}
